package org.kukker.upcoming;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.kukker.event.Event;
import org.kukker.event.EventSearchParameters;
import org.kukker.event.IEventProvider;
import org.kukker.event.IEventSearchListener;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.util.Log;
import android.xml.dom.DocumentImpl;
import android.xml.dom.ElementImpl;

public class UpcomingWebService extends WebService implements IEventProvider {

	public String apiKey;
	public String method = "event.search";
	public String searchText = "";
	public String location = "Beijing";
	public int perPage = 20;
	public int page = 1;

	String base = "http://upcoming.yahooapis.com/services/rest";
	String address = "http://upcoming.yahooapis.com/services/rest/?api_key="
			+ apiKey + "&method=" + method + "&search_text=" + searchText
			+ "&location=" + location;

	private byte mMethod = Method.UNDEFINED;
	private Properties mParameters;

	public void setSearchText(String text) {
		this.searchText = text;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	public UpcomingWebService() {
		apiKey = "6efc1a7606";
	}

	public UpcomingWebService(String apiKey) {
		this.apiKey = apiKey;
	}

	public static class Method {
		final static public byte UNDEFINED = 1;
		final static public byte EVENT_SEARCH = 1;
		final static public byte EVENT_GETINFO = 2;
		final static public byte EVENT_ADD = 3;
		final static public byte EVENT_EDIT = 4;
	}

	public Properties getParameters() {
		return this.mParameters;
	}

	public void setParameters(Properties parameters) {
		this.mParameters = parameters;
		
		
		//process properties
		//the keys are predefined  
		
		
		String location = this.mParameters.getProperty("location");		
		String searchText = this.mParameters.getProperty("search_text");
		if(location != null){
			this.location = location;
		}
		if(searchText != null){
			this.searchText = searchText;	
		}
	}

	public void setMethod(byte upcoming_method) {
		this.mMethod = upcoming_method;
	}

	private String generateRestUri() {
		String uri = "";
		if (mMethod == Method.EVENT_SEARCH) {
			try {
			uri = this.base + 
			 "/?api_key=" + this.apiKey  
			 + "&location=" + URLEncoder.encode(this.location, "UTF-8") 
			 + "&search_text=" + URLEncoder.encode(this.searchText, "UTF-8")
			 + "&method=" + "event.search"  
			 + "&per_page=" + this.perPage
			 + "&page=" + this.page;
			} catch (UnsupportedEncodingException e1) {				
				e1.printStackTrace();
			}
			
			Log.i("webservice","call: "+uri);
		}
		return uri;
	}

	public InputStream invoke(String uri) {
		Log.i("UpcomingWebService", "invoke() uri: " + uri);
		InputStream content = null;
		if (uri.compareTo("") != 0) {
			URL url;
			try {
				url = new URL(uri);
				content = (InputStream) url.getContent();
				return content;
			} catch (MalformedURLException e) {				
				e.printStackTrace();				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}
	
	/**
	 * Invoke webservice call and return the result in arraylist 
	 * @param eventsArrayList
	 * @return number of new events added
	 */
	public int get(ArrayList<Event> eventsArrayList) {
		InputStream content = invoke(generateRestUri());		
		DocumentImpl doc = parseResult(content);
		if(doc == null){
			return 0;
		}
		NodeList eventNodes = doc.getElementsByTagName("event");
		if(eventNodes == null){
			return 0;
		}
		
		int numEvents = eventNodes.getLength();
		if(numEvents == 0){
			return 0;
		}
		
		//Log.i("debug","upcoming.org events found total:"+events.length);
		int i = 0;
		try{
			for (; i < numEvents; i++) {	
				Log.i("service2","i:"+i);
				ElementImpl el = (ElementImpl) eventNodes.item(i);
				
				UpcomingEvent e = new UpcomingEvent();				
				
				e.name = el.getAttribute("name");
				e.description = el.getAttribute("description");				
				e.startDate = el.getAttribute("start_date");				
				e.endDate = el.getAttribute("end_date");				
				e.startTime = el.getAttribute("start_time");				
				e.remoteId = Integer.parseInt(el.getAttribute("id"));
				e.venueName = el.getAttribute("venue_name");
				e.venueAddress = el.getAttribute("venue_address");
				e.venueCity = el.getAttribute("venue_city");
				e.venueCountry = el.getAttribute("venue_country_name");
				e.url = el.getAttribute("url");
				e.longitude = el.getAttribute("longitude");
				e.latitude = el.getAttribute("latitude");
				
				//TODO re-architect this				
				e.originId = 1;
				e.typeId = 1;
					
				if(this.mOnEventFoundListener != null){
					this.mOnEventFoundListener.onEventFound(e);
				}
				eventsArrayList.add(e);
			}	
		}
		catch(Exception e){
			return i;
		}
		return i;		
	}
	
	/*
	public Event[] get() {
		InputStream content = invoke(generateRestUri());		
		DocumentImpl doc = parseResult(content);
		if(doc == null){
			return null;
		}
		NodeList eventNodes = doc.getElementsByTagName("event");
		if(eventNodes == null){
			return null;
		}
		
		int numEvents = eventNodes.getLength();
		if(numEvents == 0){
			return null;
		}
		
		
		// convert to an array of POJO
		UpcomingEvent events[] = new UpcomingEvent[numEvents];
		
		Log.i("debug","upcoming.org events found total:"+events.length);
		try{
			for (int i = 0; i < numEvents; i++) {
				
					
				ElementImpl el = (ElementImpl) eventNodes.item(i);
				events[i] = new UpcomingEvent();
				events[i].name = el.getAttribute("name");
				events[i].description = el.getAttribute("description");
				
				events[i].startDate = el.getAttribute("start_date");				
				events[i].endDate = el.getAttribute("end_date");
				
				events[i].startTime = el.getAttribute("start_time");
				
				events[i].remoteId = Integer.parseInt(el.getAttribute("id"));
				// Log.i("debug","remoteId:"+events[i].remoteId);
				// events[i].isSaved = false;
				events[i].venueName = el.getAttribute("venue_name");
				events[i].venueAddress = el.getAttribute("venue_address");
				events[i].venueCity = el.getAttribute("venue_city");
				events[i].venueCountry = el.getAttribute("venue_country_name");

				events[i].url = el.getAttribute("url");
				events[i].longitude = el.getAttribute("longitude");
				events[i].latitude = el.getAttribute("latitude");
				
				//TODO re-architect this so that originId is retrieved dynamically.
				events[i].originId = 1;
				events[i].typeId = 1;
					
				if(this.mOnEventFoundListener != null){
					this.mOnEventFoundListener.onEventFound(events[i]);
				}
				
				
			}	
		}
		
		catch(Exception e){
			return null;
		}
		return events;
	}
	*/

	public DocumentImpl parseResult(InputStream content) {
		if (content == null) {
			return null;
		}

		DocumentBuilderFactory dbf1 = DocumentBuilderFactory.newInstance();
		dbf1.setValidating(false);
		dbf1.setExpandEntityReferences(true);
		dbf1.setIgnoringComments(true);
		dbf1.setNamespaceAware(false);

		DocumentBuilder db;
		try {
			db = dbf1.newDocumentBuilder();
			DocumentImpl doc = (DocumentImpl) db.parse(content);
			
			
			return doc;
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;

	}


	
	private IEventSearchListener mOnEventFoundListener;

	@Override
	public void setOnEventFoundListener(IEventSearchListener listener) {
		this.mOnEventFoundListener = listener;
		
	}
}

class WebService {

}
